package com.peanut.devlibrary.camera;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.CameraProfile;
import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.provider.MediaStore;
import android.provider.Settings;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.peanut.baby.R;
import com.peanut.devlibrary.BaseActivity;
import com.peanut.devlibrary.RequestResult;
import com.peanut.devlibrary.compressor.Compressor;
import com.peanut.devlibrary.util.StringUtil;
import com.tencent.mars.xlog.Log;
import com.yanzhenjie.alertdialog.AlertDialog;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.PermissionListener;
import com.yanzhenjie.permission.Rationale;
import com.yanzhenjie.permission.RationaleListener;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


/**
 * Created by anonymouslystudio on 2017/6/27.
 */

public class CameraActivity extends BaseActivity implements View.OnClickListener,
    ShutterButton.OnShutterButtonListener,SurfaceHolder.Callback{
    private static final String TAG = CameraActivity.class.getSimpleName();


    //    private static final String TAG = "CameraActivity";
    private static final int FIRST_TIME_INIT = 2;
    private static final int RESTART_PREVIEW = 3;
    private static final int CLEAR_SCREEN_DELAY = 4;
    private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 5;

    // The subset of parameters we need to update in setCameraParameters().
    private static final int UPDATE_PARAM_INITIALIZE = 1;
    //    private static final int UPDATE_PARAM_ZOOM = 2;
    private static final int UPDATE_PARAM_PREFERENCE = 4;
    private static final int UPDATE_PARAM_ALL = -1;

    // When setCameraParametersWhenIdle() is called, we accumulate the subsets
    // needed to be updated in mUpdateSet.
    private int mUpdateSet;

    // The brightness settings used when it is set to automatic in the system.
    // The reason why it is set to 0.7 is just because 1.0 is too bright.
    private static final float DEFAULT_CAMERA_BRIGHTNESS = 0.7f;

    private static final int SCREEN_DELAY = 2 * 60 * 1000;
    private static final int FOCUS_BEEP_VOLUME = 100;


    private Camera.Parameters mParameters;
//    private Parameters mInitialParams;

    private MyOrientationEventListener mOrientationListener;
    // The device orientation in degrees. Default is unknown.
    private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
    // The orientation compensation for icons and thumbnails.
    private int mOrientationCompensation = 0;


    private static final int IDLE = 1;
    private static final int SNAPSHOT_IN_PROGRESS = 2;

    private int mStatus = IDLE;

    private Camera mCameraDevice;
    private ContentProviderClient mMediaProviderClient;
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder = null;
    private FocusRectangle mFocusRectangle;
    private ToneGenerator mFocusToneGenerator;

    private boolean mStartPreviewFail = false;

    private ImageCapture mImageCapture = null;

    private boolean mPreviewing;
    private boolean mPausing;
    private boolean mFirstTimeInitialized;


    private static final int FOCUS_NOT_STARTED = 0;
    private static final int FOCUSING = 1;
    private static final int FOCUSING_SNAP_ON_FINISH = 2;
    private static final int FOCUS_SUCCESS = 3;
    private static final int FOCUS_FAIL = 4;
    private int mFocusState = FOCUS_NOT_STARTED;

    private ContentResolver mContentResolver;
    private boolean mDidRegister = false;

    private ShutterCallback mShutterCallback = new ShutterCallback();
    private final PostViewPictureCallback mPostViewPictureCallback =
            new PostViewPictureCallback();
    private final RawPictureCallback mRawPictureCallback =
            new RawPictureCallback();
    private final AutoFocusCallback mAutoFocusCallback =
            new AutoFocusCallback();

    // Use the ErrorCallback to capture the crash count
    // on the mediaserver
    private final ErrorCallback mErrorCallback = new ErrorCallback();

    private long mFocusStartTime;
    private long mFocusCallbackTime;
    private long mCaptureStartTime;
    private long mShutterCallbackTime;
    private long mPostViewPictureCallbackTime;
    private long mRawPictureCallbackTime;
    private long mJpegPictureCallbackTime;
    private int mPicturesRemaining;

    // These latency time are for the CameraLatency test.
    public long mAutoFocusTime;
    public long mShutterLag;
    public long mShutterToPictureDisplayedTime;
    public long mPictureDisplayedToJpegCallbackTime;
    public long mJpegCallbackFinishTime;
    public long mCloseAnimStartTime;

    // Add for test
    public static boolean mMediaServerDied = false;
    private boolean 	mStartCam = false;

    // Focus mode. Options are pref_camera_focusmode_entryvalues.
    private String mFocusMode;
    private final Handler mHandler = new MainHandler();
    private int mNumberOfCameras;
    private int mCameraId;


    private ShutterButton 					mShutterButton; 	//拍照按键
    private ImageView mTurnCamera;	  	//切换摄像头按键

    private ImageView mFlash;				//闪光灯
    private ImageView	  					mBack;	  			//返回

    private ImageView	  					mChooseLocal;	  			//返回

    private int    mScreenWidth,mScreenHeight;

    private List<String>              supportedFlashMode;


    /**
     *
     *
     * This Handler is used to post message back onto the main thread of the
     * application
     */
    @SuppressLint("HandlerLeak")
    private class MainHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case RESTART_PREVIEW:
                    restartPreview();
                    if (mJpegPictureCallbackTime != 0) {
                        long now = System.currentTimeMillis();
                        mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;

                        mJpegPictureCallbackTime = 0;
                    }


                    break;
                case CLEAR_SCREEN_DELAY:
                    getWindow().clearFlags(
                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    break;


                case FIRST_TIME_INIT: {
                    initializeFirstTime();
                    break;
                }

                case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
                    setCameraParametersWhenIdle(0);
                    break;
                }
            }
        }
    }


    /**
     *
     */
    private boolean requestResult = false;

    public static void start(Context ctx){
        ctx.startActivity(new Intent(ctx,CameraActivity.class));
    }

    public static void startForResult(Activity activity){
        activity.startActivityForResult(new Intent(activity,CameraActivity.class).putExtra("requestResult",true), RequestResult.REQUEST_CODE_CAMERA);
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        if(getSupportActionBar() != null){
            getSupportActionBar().hide();
        }
        requestResult = getIntent().getBooleanExtra("requestResult",false);

        setContentView(R.layout.library_activity_camera);

        mScreenWidth = getResources().getDisplayMetrics().widthPixels;
        mScreenHeight = getResources().getDisplayMetrics().heightPixels;


        mBack = (ImageView) findViewById(R.id.camera_close);
        mBack.setOnClickListener(CameraActivity.this);
        mFlash = (ImageView) findViewById(R.id.camera_flash);
        mFlash.setOnClickListener(this);



        mTurnCamera = (ImageView) findViewById(R.id.camera_switch);
        mTurnCamera.setOnClickListener(CameraActivity.this);

        mChooseLocal = (ImageView) findViewById(R.id.camera_preview);
        mChooseLocal.setOnClickListener(CameraActivity.this);

        mShutterButton = (ShutterButton) findViewById(R.id.camera_shoot);
        mShutterButton.setOnShutterButtonListener(this);


        mSurfaceView = (SurfaceView) findViewById(R.id.camera_surface);
        mSurfaceView.setOnTouchListener(mSurfaceOnTouchListener);


        mFocusRectangle = (FocusRectangle) findViewById(R.id.focus_rectangle);




        checkPermission();

    }

    private synchronized void  checkPermission(){
        if(hasPermission()){
            initialStartPreview();
            return;
        }
        AndPermission.with(this)
                .requestCode(101)
                .permission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .rationale(rationaleListener)
                .callback(new PermissionListener() {
                    @Override
                    public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {
                        Log.d("LauncherActivity","PermissionListener.SUCCESS");
                        initialStartPreview();
//                        restartActivity();
                    }

                    @Override
                    public void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {
                        Log.d("LauncherActivity","PermissionListener.FAIL");
                        onPermissionDenied();
                    }
                })
                .start();
    }

    private void restartActivity(){
        CameraActivity.start(this);
        finish();
    }


    private RationaleListener rationaleListener = new RationaleListener() {
        @Override
        public void showRequestPermissionRationale(int requestCode,final Rationale rationale) {
            AlertDialog.newBuilder(CameraActivity.this)
                    .setTitle("提示")
                    .setMessage("相机需要相机和写本地文件的权限，否则相机将不可用！")
                    .setPositiveButton("同意", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            rationale.resume();
                        }
                    })
                    .setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            rationale.cancel();
                        }
                    })
                    .show();
        }
    };


    private void onPermissionDenied(){
        showToast("请赋予应用相机和文件权限后再试");
        finish();
    }

    private void initialStartPreview(){
        Log.d(TAG,"initialStartPreview...");
        mNumberOfCameras = CameraHolder.instance().getNumberOfCameras();

        /*
         * To reduce startup time, we start the preview in another thread.
         * We make sure the preview is started at the end of onCreate.
         */
        Thread startPreviewThread = new Thread(new Runnable() {
            public void run() {
                try {
                    mStartPreviewFail = false;
                    startPreview();
                } catch (CameraHardwareException e) {
                    // In eng build, we throw the exception so that test tool
                    // can detect it and report it
                    if ("eng".equals(Build.TYPE)) {
                        throw new RuntimeException(e);
                    }
                    mStartPreviewFail = true;
                }
            }
        });
        startPreviewThread.start();

        // don't set mSurfaceHolder here. We have it set ONLY within
        // surfaceChanged / surfaceDestroyed, other parts of the code
        // assume that when it is set, the surface is also set.
        SurfaceHolder holder = mSurfaceView.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


        // Make sure preview is started.
        try {
            startPreviewThread.join();
            if (mStartPreviewFail) {
                showCameraErrorAndFinish();
                return;
            }
        } catch (InterruptedException ex) {
            // ignore
        }

    }


    private void keepMediaProviderInstance() {
        if (mMediaProviderClient == null) {
            mMediaProviderClient = getContentResolver()
                    .acquireContentProviderClient(MediaStore.AUTHORITY);
        }
    }

    // Snapshots can only be taken after this is called. It should be called
    // once only. We could have done these things in onCreate() but we want to
    // make preview screen appear as soon as possible.
    private void initializeFirstTime() {
        if (mFirstTimeInitialized) return;

        // Create orientation listenter. This should be done first because it
        // takes some time to get first orientation.
        mOrientationListener = new MyOrientationEventListener(CameraActivity.this);
        mOrientationListener.enable();


        keepMediaProviderInstance();
        checkStorage();

        // Initialize last picture button.
        mContentResolver = getContentResolver();


        updateFocusIndicator();

        initializeScreenBrightness();
        installIntentFilter();
        initializeFocusTone();

        mFirstTimeInitialized = true;
        addIdleHandler();
    }

    private void addIdleHandler() {
        MessageQueue queue = Looper.myQueue();
        queue.addIdleHandler(new MessageQueue.IdleHandler() {
            public boolean queueIdle() {
                ImageManager.ensureOSXCompatibleFolder();
                return false;
            }
        });
    }

    // If the activity is paused and resumed, this method will be called in
    // onResume.
    private void initializeSecondTime() {
        // Start orientation listener as soon as possible because it takes
        // some time to get first orientation.
        mOrientationListener.enable();


        installIntentFilter();
        initializeFocusTone();
        keepMediaProviderInstance();
        checkStorage();
//        doFocus(true);
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_MEDIA_MOUNTED)
                    || action.equals(Intent.ACTION_MEDIA_UNMOUNTED)
                    || action.equals(Intent.ACTION_MEDIA_CHECKING)) {
                checkStorage();
            } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
                checkStorage();
            }
        }
    };

    private final class ShutterCallback
            implements Camera.ShutterCallback {
        public void onShutter() {

            mShutterCallbackTime = System.currentTimeMillis();
            mShutterLag = mShutterCallbackTime - mCaptureStartTime;

            mCloseAnimStartTime = System.currentTimeMillis();
            clearFocusState();
        }
    }

    private final class PostViewPictureCallback implements Camera.PictureCallback {
        public void onPictureTaken(
                byte [] data, Camera camera) {
            mPostViewPictureCallbackTime = System.currentTimeMillis();

        }
    }

    private final class RawPictureCallback implements Camera.PictureCallback {
        public void onPictureTaken(
                byte [] rawData, Camera camera) {
            mRawPictureCallbackTime = System.currentTimeMillis();

        }
    }

    private final class JpegPictureCallback implements Camera.PictureCallback {

        public JpegPictureCallback() {

        }

        public void onPictureTaken(
                final byte [] jpegData, final Camera camera) {
            if (mPausing) {
                return;
            }

            if(mCameraDevice != null){
                mCameraDevice.stopPreview();
            }

            mJpegPictureCallbackTime = System.currentTimeMillis();

            if (mPostViewPictureCallbackTime != 0) {
                mShutterToPictureDisplayedTime =
                        mPostViewPictureCallbackTime - mShutterCallbackTime;
                mPictureDisplayedToJpegCallbackTime =
                        mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
            } else {
                mShutterToPictureDisplayedTime =
                        mRawPictureCallbackTime - mShutterCallbackTime;
                mPictureDisplayedToJpegCallbackTime =
                        mJpegPictureCallbackTime - mRawPictureCallbackTime;
            }

            mImageCapture.storeImage(jpegData, camera);

            // Calculate this in advance of each shot so we don't add to shutter
            // latency. It's true that someone else could write to the SD card in
            // the mean time and fill it, but that could have happened between the
            // shutter press and saving the JPEG too.
            calculatePicturesRemaining();

            if (mPicturesRemaining < 1) {
                updateStorageHint(mPicturesRemaining);
            }

            if (!mHandler.hasMessages(RESTART_PREVIEW)) {
                long now = System.currentTimeMillis();
                mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;

                mJpegPictureCallbackTime = 0;
            }

            final String path = mImageCapture.getFilePath();
            final int degree = mOrientationCompensation;
            final boolean isFront = isFrontCamera(mCameraDevice);

            new Thread(new Runnable() {

                @Override
                public void run() {
                    //TODO  here to compress your picture
                    File compressed = Compressor.compress(new File(mImageCapture.getFilePath()));
                    Log.d(TAG,"compressed result: "+compressed.getAbsolutePath());
                    onPictureStored(mImageCapture.getFilePath());


//                    try {
//                        if (CameraResultImageHandler.handleImages(path, isFront, degree, mScreenWidth, mScreenHeight)) {
//                            switchToFilter(path);
//                        } else {
//                            showToast(getString(R.string.failed));
//                        }
//                    } catch (Exception e) {
//                        e.printStackTrace();
//
//                    }
                }
            }).start();

//            handler.post(new Runnable() {
//
//				@Override
//				public void run() {
//					try {
//						if (CameraResultImageHandler.handleImages(path, isFront, degree, mScreenWidth, mScreenHeight)) {
//							switchToFilter(path);
//						} else {
//							showToast(getString(R.string.failed));
//						}
//					} catch (Exception e) {
//						e.printStackTrace();
//
//					}
//
//				}
//			});

        }
    }


    private void onPictureStored(final String path){

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(requestResult){
                    Intent intent = new Intent();
                    intent.putExtra("result",path);
                    setResult(RESULT_OK,intent);
                    finish();
                }else{
                    Glide.with(CameraActivity.this).load(new File(path)).into(mChooseLocal);
                    restartPreview();
                }

            }
        });

    }

    /**
     * 当前摄像头是不是前置摄像头
     * @param camera
     * @return
     */
    private boolean isFrontCamera(Camera camera){
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(mCameraId, info);
        if(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            return true;
        }else{
            return false;
        }
    }

    private final class AutoFocusCallback
            implements Camera.AutoFocusCallback {
        public void onAutoFocus(
                boolean focused, Camera camera) {
            mFocusCallbackTime = System.currentTimeMillis();
            mAutoFocusTime = mFocusCallbackTime - mFocusStartTime;

            if (mFocusState == FOCUSING_SNAP_ON_FINISH) {

                if (focused) {
                    mFocusState = FOCUS_SUCCESS;
                } else {
                    mFocusState = FOCUS_FAIL;
                }
                mImageCapture.onSnap();
            } else if (mFocusState == FOCUSING) {

                if (focused) {
                    mFocusState = FOCUS_SUCCESS;
                } else {
                    mFocusState = FOCUS_FAIL;
                }
            } else if (mFocusState == FOCUS_NOT_STARTED) {

            }
            updateFocusIndicator();
        }
    }

    private static final class ErrorCallback
            implements Camera.ErrorCallback {
        public void onError(int error, Camera camera) {
            if (error == Camera.CAMERA_ERROR_SERVER_DIED) {
                mMediaServerDied = true;

            }
        }
    }


    /**
     * 更改闪光灯
     * @param
     */
    public void changeFlashMode(){
        //TODO
        if(mCameraDevice == null){
            showToast("操作异常，相机device不存在");
            return;
        }

        Camera.Parameters params = mCameraDevice.getParameters();
        String nextParams = getNextFlashMode(params.getFlashMode());
        Log.d(TAG,"current flashMode: "+params.getFlashMode()+" | next flash mode: "+nextParams);
        List<String> supportedParams = params.getSupportedFlashModes();
//        if(supportedParams == null || supportedParams.size() <=0){
//            return;
//        }
//        //
//        for(int i=0;i<supportedParams.size();i++){
//            Log.d(TAG,"supported flash mode: "+supportedParams.get(i));
//        }
//        String targetMode = isOpen? Camera.Parameters.FLASH_MODE_ON: Camera.Parameters.FLASH_MODE_OFF;
        if(supportedParams.indexOf(nextParams) >= 0){
            //支持闪光灯
            params.setFlashMode(nextParams);
            mCameraDevice.setParameters(params);
            if(nextParams.equals(Camera.Parameters.FLASH_MODE_AUTO)){
                mFlash.setImageResource(R.drawable.library_camera_flash_auto);
            }else if(nextParams.equals(Camera.Parameters.FLASH_MODE_ON)){
                mFlash.setImageResource(R.drawable.library_camera_flash_on);
            }else if(nextParams.equals(Camera.Parameters.FLASH_MODE_OFF)){
                mFlash.setImageResource(R.drawable.library_camera_flash_off);
            }

        }else{
            //不支持
            showToast("设备不支持闪光灯");
        }


    }


    private class ImageCapture {
        String mPath = "";

        // Returns the rotation degree in the jpeg header.
        private int storeImage(byte[] data) {
            try {
                long dateTaken = System.currentTimeMillis();
                String title = createName(dateTaken);
                String filename = title + ".jpg";
                int[] degree = new int[1];
                ImageManager.addImage(
                        mContentResolver,
                        title,
                        dateTaken,
                        ImageManager.CAMERA_IMAGE_BUCKET_NAME, filename,
                        null, data,
                        degree);
                mPath = ImageManager.CAMERA_IMAGE_BUCKET_NAME+"/"+filename;

                Uri localUri = Uri.fromFile(new File(mPath));
                Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
                sendBroadcast(localIntent);
                return degree[0];
            } catch (Exception ex) {

                return 0;
            }
        }

        public void storeImage(final byte[] data,
                               Camera camera) {
            storeImage(data);
        }

        /**
         * Initiate the capture of an image.
         */
        public void initiate() {
            if (mCameraDevice == null) {
                return;
            }

            capture();
        }

        public String getFilePath(){
            return mPath;
        }

        @SuppressLint("DefaultLocale")
        private void capture() {
            // See android.hardware.Camera.Parameters.setRotation for
            // documentation.
            int rotation = 0;
            if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
                Camera.CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
                if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                    rotation = (info.orientation - mOrientation + 360) % 360;
                } else {  // back-facing camera
                    rotation = (info.orientation + mOrientation) % 360;
                }
            }
            mParameters.setRotation(rotation);

            // Clear previous GPS location from the parameters.
            mParameters.removeGpsData();

            boolean isSupported = isSupported(mCameraDevice.getParameters().getFlashMode(), mParameters.getSupportedFlashModes());
            if(isSupported){
                mParameters.setFlashMode(mCameraDevice.getParameters().getFlashMode());
            }

//            try {
//                boolean isFlashOn = mFlash.isChecked();
//                if(isFlashOn){
//                    boolean isSupported = isSupported(Camera.Parameters.FLASH_MODE_ON, mParameters.getSupportedFlashModes());
//                    if(isSupported){
//                        mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
//                    }
//                }else{
//                    boolean isSupported = isSupported(Camera.Parameters.FLASH_MODE_OFF, mParameters.getSupportedFlashModes());
//                    if(isSupported){
//                        mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
//                    }
//                }
//
//            } catch (Exception e) {
//
//            }

//            Logger.d(TAG, "capture-->"+mParameters.getPictureSize().width+"  "+mParameters.getPictureSize().height);
            mCameraDevice.setParameters(mParameters);

            mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
                    mPostViewPictureCallback, new JpegPictureCallback());
            mPreviewing = false;
        }

        public void onSnap() {
            // If we are already in the middle of taking a snapshot then ignore.
            if (mPausing || mStatus == SNAPSHOT_IN_PROGRESS) {
                return;
            }
            mCaptureStartTime = System.currentTimeMillis();
            mPostViewPictureCallbackTime = 0;
//            mHeadUpDisplay.setEnabled(false);
            mStatus = SNAPSHOT_IN_PROGRESS;

            mImageCapture.initiate();
        }

        private void clearLastData() {
        }
    }

    @SuppressLint("SimpleDateFormat")
    private String createName(long dateTaken) {
        Date date = new Date(dateTaken);
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                getString(R.string.image_file_name_format));

        return dateFormat.format(date);
    }


    public static int roundOrientation(int orientation) {
        return ((orientation + 45) / 90 * 90) % 360;
    }

    private class MyOrientationEventListener
            extends OrientationEventListener {
        public MyOrientationEventListener(Context context) {
            super(context);
        }

        @Override
        public void onOrientationChanged(int orientation) {
            // We keep the last known orientation. So if the user first orient
            // the camera then point the camera to floor or sky, we still have
            // the correct orientation.
            if (orientation == ORIENTATION_UNKNOWN) return;
            mOrientation = roundOrientation(orientation);
            // When the screen is unlocked, display rotation may change. Always
            // calculate the up-to-date orientationCompensation.
            int orientationCompensation = mOrientation
                    + Util.getDisplayRotation(CameraActivity.this);
            if (mOrientationCompensation != orientationCompensation) {
                mOrientationCompensation = orientationCompensation;

            }
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mMediaProviderClient != null) {
            mMediaProviderClient.release();
            mMediaProviderClient = null;
        }
    }

    private void checkStorage() {
        calculatePicturesRemaining();
        updateStorageHint(mPicturesRemaining);
    }

    public void onClick(View v) {
//    	Logger.d(TAG, "onClick-->"+mPausing);
        if (mPausing) {
            return;
        }
        int id = v.getId();
        if(id == R.id.camera_switch){
            if(mNumberOfCameras >1){
                switchCameraId((mCameraId + 1) % mNumberOfCameras);
            }
        }else if(id == R.id.camera_close){
            back();
        }else if(id == R.id.camera_preview){
            //TODO
            switchToLocal();
        }else if(id == R.id.camera_flash){
            changeFlashMode();
        }else if(id == R.id.camera_shoot){
            doSnap();
        }
    }



    /**
     * 跳转到相机
     */
    private void switchToLocal(){
        //TODO
//        Intent intent = new Intent(CameraActivity.this, AlbumsActivity.class);
//        startActivity(intent);
//        switchTransition();
//        finish();
    }
    @SuppressLint("SimpleDateFormat")
    private File getOutputMediaFile() {
        // get the mobile Pictures directory
        File picDir = Environment
                .getExternalStorageDirectory();

        // get the current time
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());

        return new File(picDir.getPath() + File.separator + "IMAGE_"
                + timeStamp + ".jpg");
    }

    public void onShutterButtonFocus(ShutterButton button, boolean pressed) {
        Log.d(TAG,"onShutterButtonFocus: "+pressed);
        if (mPausing) {
            return;
        }
        if(button.getId() == R.id.camera_shoot){
            doFocus(pressed);
        }

    }



    public void onShutterButtonClick(ShutterButton button) {
        Log.d(TAG,"onShutterButtonClick: ");
        if (mPausing) {
            return;
        }

        if(button.getId() == R.id.camera_shoot){
            doSnap();
        }

    }

    private OnScreenHint mStorageHint;

    private void updateStorageHint(int remaining) {
        String noStorageText = null;

        if (remaining == MenuHelper.NO_STORAGE_ERROR) {
            String state = Environment.getExternalStorageState();
            if (state == Environment.MEDIA_CHECKING) {
                noStorageText = getString(R.string.preparing_sd);
            } else {
                noStorageText = getString(R.string.no_storage);
            }
        } else if (remaining == MenuHelper.CANNOT_STAT_ERROR) {
            noStorageText = getString(R.string.access_sd_fail);
        } else if (remaining < 1) {
            noStorageText = getString(R.string.not_enough_space);
        }

        if (noStorageText != null) {
            if (mStorageHint == null) {
                mStorageHint = OnScreenHint.makeText(this, noStorageText);
            } else {
                mStorageHint.setText(noStorageText);
            }
            mStorageHint.show();
        } else if (mStorageHint != null) {
            mStorageHint.cancel();
            mStorageHint = null;
        }
    }

    private void installIntentFilter() {
        // install an intent filter to receive SD card related events.
        IntentFilter intentFilter =
                new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
        intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
        intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING);
        intentFilter.addDataScheme("file");
        registerReceiver(mReceiver, intentFilter);
        mDidRegister = true;
    }

    private void initializeFocusTone() {
        // Initialize focus tone generator.
        try {
            mFocusToneGenerator = new ToneGenerator(
                    AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
        } catch (Throwable ex) {

            mFocusToneGenerator = null;
        }
    }

    private void initializeScreenBrightness() {
        Window win = getWindow();
        // Overright the brightness settings if it is automatic
        int mode = Settings.System.getInt(
                getContentResolver(),
                Settings.System.SCREEN_BRIGHTNESS_MODE,
                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
        if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
            WindowManager.LayoutParams winParams = win.getAttributes();
            winParams.screenBrightness = DEFAULT_CAMERA_BRIGHTNESS;
            win.setAttributes(winParams);
        }
    }


    @Override
    protected void onResume() {
        super.onResume();

        System.gc();

        mPausing = false;
        mJpegPictureCallbackTime = 0;
        mImageCapture = new ImageCapture();

        // Start the preview if it is not started.

        if(!hasPermission()){
            return;
        }
        if (!mPreviewing && !mStartPreviewFail) {

            if (!restartPreview()) return;
        }

        if (mSurfaceHolder != null) {
            // If first time initialization is not finished, put it in the
            // message queue.
            if (!mFirstTimeInitialized) {
                mHandler.sendEmptyMessage(FIRST_TIME_INIT);
            } else {
                initializeSecondTime();
            }
        }
        keepScreenOnAwhile();
    }

    private boolean hasPermission(){
        return AndPermission.hasPermission(this,Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

    @Override
    protected void onPause() {

        mPausing = true;
        stopPreview();
        // Close the camera now because other activities may need to use it.
        closeCamera();
        resetScreenOn();
        if (mFirstTimeInitialized) {
            mOrientationListener.disable();
        }

        if (mDidRegister) {
            unregisterReceiver(mReceiver);
            mDidRegister = false;
        }


        if (mFocusToneGenerator != null) {
            mFocusToneGenerator.release();
            mFocusToneGenerator = null;
        }

        if (mStorageHint != null) {
            mStorageHint.cancel();
            mStorageHint = null;
        }

        // If we are in an image capture intent and has taken
        // a picture, we just clear it in onPause.
        mImageCapture.clearLastData();
        mImageCapture = null;

        // Remove the messages in the event queue.
        mHandler.removeMessages(RESTART_PREVIEW);
        mHandler.removeMessages(FIRST_TIME_INIT);

        super.onPause();

        System.gc();
    }

    private boolean canTakePicture() {
        return isCameraIdle() && mPreviewing && (mPicturesRemaining > 0);
    }

    private void autoFocus() {
        // Initiate autofocus only when preview is started and snapshot is not
        // in progress.
        if (canTakePicture()) {
//            mHeadUpDisplay.setEnabled(false);

            mFocusStartTime = System.currentTimeMillis();
            mFocusState = FOCUSING;
            updateFocusIndicator();
            try {
                mCameraDevice.autoFocus(mAutoFocusCallback);
            } catch (Exception e) {

            }
        }
    }

    private void cancelAutoFocus() {
        // User releases half-pressed focus key.
        if (mStatus != SNAPSHOT_IN_PROGRESS && (mFocusState == FOCUSING
                || mFocusState == FOCUS_SUCCESS || mFocusState == FOCUS_FAIL)) {

            mCameraDevice.cancelAutoFocus();
        }
        if (mFocusState != FOCUSING_SNAP_ON_FINISH) {
            clearFocusState();
        }
    }

    private void clearFocusState() {
        mFocusState = FOCUS_NOT_STARTED;
        updateFocusIndicator();
    }

    private void updateFocusIndicator() {
        if (mFocusRectangle == null) return;

        if (mFocusState == FOCUSING || mFocusState == FOCUSING_SNAP_ON_FINISH) {
            mFocusRectangle.showStart();
        } else if (mFocusState == FOCUS_SUCCESS) {
            mFocusRectangle.showSuccess();
        } else if (mFocusState == FOCUS_FAIL) {
            mFocusRectangle.showFail();
        } else {
            mFocusRectangle.clear();
        }
    }

    @Override
    public void onBackPressed() {
        if (!isCameraIdle()) {
            // ignore backs while we're taking a picture
            return;
        }
        super.onBackPressed();
    }

    private void back() {
        //TODO
        finish();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_FOCUS:
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    doFocus(true);
                }
                return true;
            case KeyEvent.KEYCODE_CAMERA:
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    doSnap();
                }
                return true;
            case KeyEvent.KEYCODE_BACK:
                back();

                return true;
            default:
                break;
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_FOCUS:
                if (mFirstTimeInitialized) {
                    doFocus(false);
                }
                return true;
        }
        return super.onKeyUp(keyCode, event);
    }

    private void doSnap() {
        Log.d(TAG,"doSnap: "+mFocusMode+" "+mFocusState);
        // If the user has half-pressed the shutter and focus is completed, we
        // can take the photo right away. If the focus mode is infinity, we can
        // also take the photo.
        if (mFocusMode.equals(Camera.Parameters.FOCUS_MODE_INFINITY)
                || mFocusMode.equals(Camera.Parameters.FOCUS_MODE_FIXED)
                || mFocusMode.equals(Camera.Parameters.FOCUS_MODE_EDOF)
                || (mFocusState == FOCUS_SUCCESS
                || mFocusState == FOCUS_FAIL)) {
            mImageCapture.onSnap();
        } else if (mFocusState == FOCUSING) {
            // Half pressing the shutter (i.e. the focus button event) will
            // already have requested AF for us, so just request capture on
            // focus here.
            mFocusState = FOCUSING_SNAP_ON_FINISH;
        } else if (mFocusState == FOCUS_NOT_STARTED) {
            // Focus key down event is dropped for some reasons. Just ignore.
        }
    }

    private void doFocus(boolean pressed) {
        // Do the focus if the mode is not infinity.
//        if (mHeadUpDisplay.collapse()) return;
        if (!(mFocusMode.equals(Camera.Parameters.FOCUS_MODE_INFINITY)
                || mFocusMode.equals(Camera.Parameters.FOCUS_MODE_FIXED)
                || mFocusMode.equals(Camera.Parameters.FOCUS_MODE_EDOF))) {
            if (pressed) {  // Focus key down.
                autoFocus();
            } else {  // Focus key up.
                cancelAutoFocus();
            }
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        mSurfaceView.setBackgroundColor(Color.TRANSPARENT);
        // Make sure we have a surface in the holder before proceeding.
        if (holder.getSurface() == null) {

            return;
        }

        // We need to save the holder for later use, even when the mCameraDevice
        // is null. This could happen if onResume() is invoked after this
        // function.
        mSurfaceHolder = holder;

        // The mCameraDevice will be null if it fails to connect to the camera
        // hardware. In this case we will show a dialog and then finish the
        // activity, so it's OK to ignore it.
        if (mCameraDevice == null) return;

        // Sometimes surfaceChanged is called after onPause or before onResume.
        // Ignore it.
        if (mPausing || isFinishing()) return;

        if (mPreviewing && holder.isCreating()) {
            // Set preview display if the surface is being created and preview
            // was already started. That means preview display was set to null
            // and we need to set it now.
            setPreviewDisplay(holder);
        } else {
            // 1. Restart the preview if the size of surface was changed. The
            // framework may not support changing preview display on the fly.
            // 2. Start the preview now if surface was destroyed and preview
            // stopped.
            checkPermission();

        }

        // If first time initialization is not finished, send a message to do
        // it later. We want to finish surfaceChanged as soon as possible to let
        // user see preview first.
        if (!mFirstTimeInitialized) {
            mHandler.sendEmptyMessage(FIRST_TIME_INIT);
        } else {
            initializeSecondTime();
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        mSurfaceView.setBackgroundColor(Color.BLACK);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        stopPreview();
        mSurfaceHolder = null;
    }

    private void closeCamera() {
        if (mCameraDevice != null) {
            CameraHolder.instance().release();
            mCameraDevice.setZoomChangeListener(null);
            mCameraDevice = null;
            mPreviewing = false;
        }
    }

    private void ensureCameraDevice() throws CameraHardwareException {
        if (mCameraDevice == null) {
            mCameraDevice = CameraHolder.instance().open(mCameraId);
//            mInitialParams = mCameraDevice.getParameters();
        }
    }


    private void showCameraErrorAndFinish() {
        Resources ress = getResources();
        Util.showFatalErrorAndFinish(CameraActivity.this,
                ress.getString(R.string.exception),
                ress.getString(R.string.cannot_connect_camera));
    }


    private boolean restartPreview() {
        try {
            startPreview();
        } catch (CameraHardwareException e) {
            showCameraErrorAndFinish();
            return false;
        }
        return true;
    }

    private void setPreviewDisplay(SurfaceHolder holder) {
        try {
            mCameraDevice.setPreviewDisplay(holder);
        } catch (Throwable ex) {
            closeCamera();
            throw new RuntimeException("setPreviewDisplay failed", ex);
        }
    }

    private void startPreview() throws CameraHardwareException {
        if (mPausing || isFinishing()) return;

        ensureCameraDevice();

        // If we're previewing already, stop the preview first (this will blank
        // the screen).
        if (mPreviewing) stopPreview();

        setPreviewDisplay(mSurfaceHolder);
        Util.setCameraDisplayOrientation(this, mCameraId, mCameraDevice);
        setCameraParameters(UPDATE_PARAM_ALL);

        mCameraDevice.setErrorCallback(mErrorCallback);

        try {

            mCameraDevice.startPreview();
        } catch (Throwable ex) {
            closeCamera();
            throw new RuntimeException("startPreview failed", ex);
        }
        mPreviewing = true;
        mStatus = IDLE;



    }



    private void stopPreview() {
        if (mCameraDevice != null && mPreviewing) {

            mCameraDevice.stopPreview();
        }
        mPreviewing = false;
        // If auto focus was in progress, it would have been canceled.
        clearFocusState();
    }

    /**
     * 获取最适合的picture size
     * @param sizes
     * @param w
     * @param h
     * @return
     */
    private Camera.Size getOptimalPictureSize(List<Camera.Size> sizes, int w, int h) {
        Collections.sort(sizes,new PictureSizeComp());
//    	for(int i=0;i<sizes.size();i++){
//    		Logger.d(TAG, "SUPPORTEDD SIZE-->"+sizes.get(i).width+" "+sizes.get(i).height);
//    	}
        Camera.Size optimalSize = null;
        for(int i=0;i<sizes.size();i++){
            Camera.Size size = sizes.get(i);
            if(size.width >= w && size.height >= h){
                optimalSize = size;
                break;
            }
        }
        // 如果没有长宽都大于屏幕长宽的 则取最大的分辨率
        if(optimalSize == null){
            optimalSize = sizes.get(sizes.size() - 1);
        }
//    	Logger.d(TAG, "getOptimalPictureSize-->"+optimalSize.width+" "+optimalSize.height);
        return optimalSize;
    }

    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, double targetRatio) {
        final double ASPECT_TOLERANCE = 0.05;
        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        // Because of bugs of overlay and layout, we sometimes will try to
        // layout the viewfinder in the portrait orientation and thus get the
        // wrong size of mSurfaceView. When we change the preview size, the
        // new overlay will be created before the old one closed, which causes
        // an exception. For now, just get the screen size

        int targetHeight = Math.min(mScreenHeight, mScreenWidth);

        if (targetHeight <= 0) {
            targetHeight = mScreenHeight;
        }

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }

//        Logger.d(TAG, "getOptimalPreviewSize-->"+optimalSize.width+" "+optimalSize.height);

        return optimalSize;
    }

    private static boolean isSupported(String value, List<String> supported) {
        return supported == null ? false : supported.indexOf(value) >= 0;
    }

    @SuppressWarnings("deprecation")
    private void updateCameraParametersInitialize() {

        // Reset preview frame rate to the maximum because it may be lowered by
        // video camera application.
        List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates();
        if (frameRates != null) {
            Integer max = Collections.max(frameRates);
            mParameters.setPreviewFrameRate(max);
        }

    }

    private void updateCameraParametersPreference() {

        mParameters = mCameraDevice.getParameters();
        // Set picture size.
        List<Camera.Size> SupportedPictureSize = mParameters.getSupportedPictureSizes();
        Camera.Size  targetSize = getOptimalPictureSize(SupportedPictureSize, mScreenWidth, mScreenWidth);
        mParameters.setPictureSize(targetSize.width, targetSize.height);
        try {
            mCameraDevice.setParameters(mParameters);
        } catch (Exception e1) {
//			Logger.d(TAG, "设置图片尺寸异常-->"+e1.toString());
        }finally{
            mParameters = mCameraDevice.getParameters();
        }
        // Set the preview frame aspect ratio according to the picture size.
        Camera.Size size = mParameters.getPictureSize();
        // Set a preview size that is closest to the viewfinder height and has
        // the right aspect ratio.
        List<Camera.Size> sizes = mParameters.getSupportedPreviewSizes();

        Camera.Size optimalSize = getOptimalPreviewSize(
                sizes, (double) size.width / size.height);
        if (optimalSize != null) {
            Camera.Size original = mParameters.getPreviewSize();
            if (!original.equals(optimalSize)) {
                mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
                try {
                    mCameraDevice.setParameters(mParameters);
                } catch (Exception e1) {
//					Logger.d(TAG, "设置预览尺寸异常-->"+e1.toString());
                }finally{
                    mParameters = mCameraDevice.getParameters();
                }
            }
        }
        //图片质量

        mParameters.setJpegQuality(CameraProfile.getJpegEncodingQualityParameter(CameraProfile.QUALITY_HIGH));
        try {
            mCameraDevice.setParameters(mParameters);
//			Logger.d(TAG, "图片质量-->"+mParameters.getJpegQuality());
        } catch (Exception e1) {
//			Logger.d(TAG, "设置图片质量异常-->"+e1.toString());
        }finally{
            mParameters = mCameraDevice.getParameters();
        }

        // Set focus mode.
        if(isSupported(Camera.Parameters.FOCUS_MODE_AUTO, mParameters.getSupportedFocusModes())){
            mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            try {
                mCameraDevice.setParameters(mParameters);
            } catch (Exception e1) {
//				Logger.d(TAG, "设置对焦模式-->" + e1.toString());
            } finally {
                mParameters = mCameraDevice.getParameters();
            }
        }

//        if(isSupported(Camera.Parameters.FLASH_MODE_ON, mParameters.getSupportedFlashModes())){
//            //如果支持闪光灯开，则将
//            mFlash.setClickable(true);
//            mFlash.setChecked(false);
//        }else{
//            mFlash.setClickable(false);
//            mFlash.setChecked(false);
//        }

//       mCameraDevice.setParameters(mParameters);

        mFocusMode =   Camera.Parameters.FOCUS_MODE_AUTO;


        //here we adjust preview height
        adjustPreviewHeight();
    }

    /**
     * 点击聚焦
     */
    private View.OnTouchListener mSurfaceOnTouchListener = new View.OnTouchListener() {

        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {
            focusOnTouch(arg1);
            return true;
        }
    };

    /**
     * 更新聚焦区域方框布局
     * @param event
     */
    private void updateFocusRectLayout(MotionEvent event){
        int x = (int) event.getRawX();
        int y = (int) event.getRawY();

        int[] visiableLocation = new int[2];


        int visiableTop = visiableLocation[1];

        int rectSize = dip2px(CameraActivity.this, 80);
        int halfRectSize = rectSize / 2;
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(rectSize, rectSize);
        params.gravity = Gravity.TOP|Gravity.LEFT;
        //判断位置
        if(x - halfRectSize <= 0){
            //DO NOTHING
        }else if(x + halfRectSize >= mScreenWidth){
            params.leftMargin = mScreenWidth - rectSize;
        }else{
            params.leftMargin = x - halfRectSize;
        }

        if(y - halfRectSize <= visiableTop){
            //do nothing
        }else if(y + halfRectSize >= visiableTop+mScreenWidth){
            params.topMargin = mScreenWidth - rectSize;
        }else{
            params.topMargin = y - visiableTop - halfRectSize;
        }

        mFocusRectangle.setLayoutParams(params);

    }

    /**
     * 更新聚焦区域方框布局
     * @param
     */
    private void resetFocusRectLayout(){
        int rectSize = dip2px(CameraActivity.this, 80);

        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(rectSize, rectSize);
        params.gravity = Gravity.CENTER;

        mFocusRectangle.setLayoutParams(params);

    }

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        public static int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }

    /**
     * @param event
     */
    @SuppressLint("NewApi")
    public void focusOnTouch(MotionEvent event) {
        if(mCameraDevice == null){
            return;
        }
        updateFocusRectLayout(event);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
            Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);
            Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f);

            mParameters = mCameraDevice.getParameters();

            if (mParameters.getMaxNumFocusAreas() > 0) {
                List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
                focusAreas.add(new Camera.Area(focusRect, 1000));

                mParameters.setFocusAreas(focusAreas);
            }

            if (mParameters.getMaxNumMeteringAreas() > 0) {
                List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
                meteringAreas.add(new Camera.Area(meteringRect, 1000));

                mParameters.setMeteringAreas(meteringAreas);
            }

            mCameraDevice.setParameters(mParameters);
            try {
                mCameraDevice.autoFocus(mAutoFocusCallback);
            } catch (Exception e) {

            }
        }

        clearFocusState();
        doFocus(true);
    }

    /**
     * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
     */
    private Rect calculateTapArea(float x, float y, float coefficient) {
        float focusAreaSize = 300;
        int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();

        int centerX = (int) (x / mScreenWidth - 1000);
        int centerY = (int) (y / mScreenHeight - 1000);

        int left = clamp(centerX - areaSize / 2, -1000, 1000);
        int top = clamp(centerY - areaSize / 2, -1000, 1000);

        RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);

        return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
    }

    private int clamp(int x, int min, int max) {
        if (x > max) {
            return max;
        }
        if (x < min) {
            return min;
        }
        return x;
    }


    private void adjustPreviewHeight(){
        if(mCameraDevice == null){
            return;
        }
        int previewHeight = mCameraDevice.getParameters().getPreviewSize().height;
        int previewWdith = mCameraDevice.getParameters().getPreviewSize().width;
        int min = -1;
        int max = -1;
        if(previewWdith > previewHeight){
            min = previewHeight;
            max = previewWdith;
        }else{
            min = previewWdith;
            max = previewHeight;
        }
        int targetHeight = max*mScreenWidth /min;

        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mScreenWidth, targetHeight);
        params.gravity = Gravity.TOP;
        mSurfaceView.setLayoutParams(params);

    }

    // We separate the parameters into several subsets, so we can update only
    // the subsets actually need updating. The PREFERENCE set needs extra
    // locking because the preference can be changed from GLThread as well.
    private void setCameraParameters(int updateSet) {
        mParameters = mCameraDevice.getParameters();

        if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
//        	Logger.d(TAG, "updateCameraParametersInitialize--");
            updateCameraParametersInitialize();
        }


        if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
//        	Logger.d(TAG, "updateCameraParametersPreference--");
            updateCameraParametersPreference();
        }

        mCameraDevice.setParameters(mParameters);
    }

    // If the Camera is idle, update the parameters immediately, otherwise
    // accumulate them in mUpdateSet and update later.
    private void setCameraParametersWhenIdle(int additionalUpdateSet) {
        mUpdateSet |= additionalUpdateSet;
        if (mCameraDevice == null) {
            // We will update all the parameters when we open the device, so
            // we don't need to do anything now.
            mUpdateSet = 0;
            return;
        } else if (isCameraIdle()) {
            setCameraParameters(mUpdateSet);
            mUpdateSet = 0;
        } else {
            if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
                mHandler.sendEmptyMessageDelayed(
                        SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
            }
        }
    }

    private boolean isCameraIdle() {
        return mStatus == IDLE && mFocusState == FOCUS_NOT_STARTED;
    }




    private int calculatePicturesRemaining() {
        mPicturesRemaining = MenuHelper.calculatePicturesRemaining();
        return mPicturesRemaining;
    }


    private void switchCameraId(int cameraId) {

        stopPreview();
        closeCamera();

        // Remove the messages in the event queue.
        mHandler.removeMessages(RESTART_PREVIEW);

        // Reset variables
        mJpegPictureCallbackTime = 0;
        resetFocusRectLayout();

        mCameraId = cameraId;
        if (!restartPreview()) return;
    }





    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        keepScreenOnAwhile();
    }

    private void resetScreenOn() {
        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    private void keepScreenOnAwhile() {
        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
    }


    /**
     *
     */
    private void toastVolumWhenSoundSet(){
        AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        int current = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC );
        if(current == 0){
            //静音
            //TODO
//			showToast(getString(R.string.camera_sound_slience));
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    /**
     *
     * @return
     */
    public List<String> getAppSupportedFlashMode(){
        if(supportedFlashMode == null){
            supportedFlashMode = new ArrayList<>();
            List<String> modes = mCameraDevice.getParameters().getSupportedFlashModes();
            if(modes != null && modes.size() > 0){
                if(modes.indexOf(Camera.Parameters.FLASH_MODE_AUTO) != -1){
                    supportedFlashMode.add(Camera.Parameters.FLASH_MODE_AUTO);
                }
                if(modes.indexOf(Camera.Parameters.FLASH_MODE_ON) != -1){
                    supportedFlashMode.add(Camera.Parameters.FLASH_MODE_ON);
                }
                if(modes.indexOf(Camera.Parameters.FLASH_MODE_OFF) != -1){
                    supportedFlashMode.add(Camera.Parameters.FLASH_MODE_OFF);
                }

            }
        }

        return supportedFlashMode;
    }

    /**
     *
     * @param currentMode
     * @return
     */
    public String getNextFlashMode(String currentMode){
        if(StringUtil.isNullOrEmpty(currentMode)){
            return Camera.Parameters.FLASH_MODE_AUTO;
        }

        int index = getAppSupportedFlashMode().indexOf(currentMode);
        if(index == -1){
            return Camera.Parameters.FLASH_MODE_AUTO;
        }
        index = index + 1;
        if(index > getAppSupportedFlashMode().size() - 1){
            index = 0;
        }
        return getAppSupportedFlashMode().get(index);

    }
}
